﻿using System;
using System.Collections.Generic;
using System.Linq;
using Castle.MicroKernel.Lifestyle;
using Castle.Windsor;

namespace Xenta
{
    /// <summary>
    /// Exposes the dependency interface.
    /// </summary>
    public interface IDependency
    {
    }

    /// <summary>
    /// Exposes the dependency which is initialized on resolve.
    /// </summary>
    public interface IInitDependencyOnResolve : IDependency
    {
        #region Methods

        /// <summary>
        /// Initializes the instance of the component.
        /// </summary>
        /// <remarks>
        /// Do not invoke this method directly. Methods is 
        /// being invoked by the dependency resolver.
        /// </remarks>
        void Initialize();

        #endregion
    }

    /// <summary>
    /// Exposes the dependency resolver interface.
    /// </summary>
    public interface IDependencyResolver : IDisposable
    {
        #region Methods

        /// <summary>
        /// Resolves the dependency by identifier.
        /// </summary>
        /// <param name="id">The identifier.</param>
        /// <returns>The dependency instance.</returns>
        IDependency Resolve(string id);

        /// <summary>
        /// Resolves the dependency by type.
        /// </summary>
        /// <param name="t">The type.</param>
        /// <returns>The dependency instance.</returns>
        IDependency Resolve(Type t);

        /// <summary>
        /// Resolves the dependency by type.
        /// </summary>
        /// <typeparam name="TDependency">The type.</typeparam>
        /// <returns>The dependency instance.</returns>
        TDependency Resolve<TDependency>()
            where TDependency : IDependency;

        /// <summary>
        /// Resolves all dependencies.
        /// </summary>
        /// <param name="t">The type.</param>
        /// <returns>The dependency instance collection.</returns>
        IEnumerable<IDependency> ResolveAll(Type t);

        /// <summary>
        /// Resolves all dependencies.
        /// </summary>
        /// <typeparam name="TDependency">The type.</typeparam>
        /// <returns>The dependency instance collection.</returns>
        IEnumerable<TDependency> ResolveAll<TDependency>()
            where TDependency : IDependency;

        #endregion
    }

    /// <summary>
    /// Represents the dependency resolver.
    /// </summary>
    public sealed class DependencyResolverImpl : IDependencyResolver
    {
        #region Fields

        private readonly IWindsorContainer _container;
        private readonly IDisposable _scope;

        #endregion

        #region Ctors

        /// <summary>
        /// Initializes a new instance of the class.
        /// </summary>
        /// <param name="container">The IoC container.</param>
        public DependencyResolverImpl(IWindsorContainer container)
        {
            _container = container;
            _scope = _container.BeginScope();
        }

        #endregion

        #region Methods

        /// <summary>
        /// Resolves the dependency by identifier.
        /// </summary>
        /// <param name="id">The identifier.</param>
        /// <returns>The dependency instance.</returns>
        public IDependency Resolve(string id)
        {
            return _container.Resolve<IDependency>(id);
        }

        /// <summary>
        /// Resolves the dependency by type.
        /// </summary>
        /// <param name="t">The type.</param>
        /// <returns>The dependency instance.</returns>
        public IDependency Resolve(Type t)
        {
            return _container.Resolve(t) as IDependency;
        }

        /// <summary>
        /// Resolves the dependency by type.
        /// </summary>
        /// <typeparam name="TDependency">The type.</typeparam>
        /// <returns>The dependency instance.</returns>
        public TDependency Resolve<TDependency>()
            where TDependency : IDependency
        {
            return _container.Resolve<TDependency>();
        }

        /// <summary>
        /// Resolves all dependencies.
        /// </summary>
        /// <param name="t">The type.</param>
        /// <returns>The dependency instance collection.</returns>
        public IEnumerable<IDependency> ResolveAll(Type t)
        {
            return _container.ResolveAll(t).Cast<IDependency>();
        }

        /// <summary>
        /// Resolves all dependencies.
        /// </summary>
        /// <typeparam name="TDependency">The type.</typeparam>
        /// <returns>The dependency instance collection.</returns>
        public IEnumerable<TDependency> ResolveAll<TDependency>()
            where TDependency : IDependency
        {
            return _container.ResolveAll<TDependency>();
        }

        /// <summary>
        /// Releases all the resolved dependecices.
        /// </summary>
        public void Dispose()
        {
            _scope.Dispose();
        }

        #endregion
    }
}
